pub mod reader;
pub mod splitor;

pub use reader::*;
pub use splitor::*;
use super::*;
use crate::common::*;

#[derive(Debug, Clone)]
pub struct FileBlock {
    pub id:usize,
    pub kind:FileKind,
}

#[derive(Debug, Clone)]
pub enum FileKind {
    Name(String),
    Data(usize, BytesMut),
    Tmp(usize, BytesMut),
    FileEnd,
}

impl FileKind {
    pub fn with_id(self, id:usize) -> FileBlock {
        FileBlock { id, kind: self }
    }
}

#[test]
fn test_read_and_split() {
    use config::File;
    let path = vec![
        "./chunk_io.toml",
        "./Cargo.toml"
    ];
    let config = config::Config::builder()
        .add_source(File::with_name("./chunk_io.toml"))
        .build()
        .unwrap();
    let source = SourcePool::from_config(config).unwrap();
    let mut reader = ReaderConfig::from_source(&source).unwrap().build();
    let mut splitor = SplitConfig::from_source(&source).unwrap().build();
    let print_write_item = |w:WriteItem| { println!("{:?}", w); };
    for p in path {
        reader.read_path(p.to_string(), |b|{
            splitor.split_file_block(b, print_write_item).expect("splitor error");
        }).expect("reader error");
    }
}
#[test]
fn test_sync_read_and_split() {
    use config::File;
    use std::thread;
    use std::sync::mpsc;
    use std::time::{Instant, Duration};
    
    let path_vec = vec![
        "../linux_dir/src/linux-5.0.1",
        "../linux_dir/src/linux-5.0.2",
        "../linux_dir/src/linux-5.0.3",
        "../linux_dir/src/linux-5.0.4",
        "../linux_dir/src/linux-5.0.5",
    ];
    
    let (start_tx, read_rx) = mpsc::channel();
    let (read_tx, split_rx) = mpsc::channel();
    let (split_tx, drop_rx) = mpsc::channel();
    
    let config = config::Config::builder()
        .add_source(File::with_name("./chunk_io.toml"))
        .build()
        .unwrap();
    let source = SourcePool::from_config(config).unwrap();
    
    let mut reader = ReaderConfig::from_source(&source).unwrap().build();
    let mut splitor = SplitConfig::from_source(&source).unwrap().build();
    
    // 用于收集计时结果
    let (time_tx, time_rx) = mpsc::channel();
    let time_tx1 = time_tx.clone();
    let time_tx2 = time_tx.clone();
    
    let t1 = thread::spawn(move || {
        let mut total_read_time = Duration::new(0, 0);
        let produce_file_block = |b| {
            read_tx.send(b).expect("read send error");
        };
        
        for path in read_rx.iter() {
            let start = Instant::now();
            reader.read_path(path, produce_file_block).expect("read error");
            let elapsed = start.elapsed();
            total_read_time += elapsed;
        }
        
        time_tx1.send(("read", total_read_time)).unwrap();
    });    
    
    let t2 = thread::spawn(move || {
        let mut total_split_time = Duration::new(0, 0);
        let produce_write_item = |w| {
            split_tx.send(w).expect("split send error");
        };
        
        for b in split_rx.iter() {
            let start = Instant::now();
            splitor.split_file_block(b, produce_write_item).expect("split error");
            let elapsed = start.elapsed();
            total_split_time += elapsed;
        }
        
        time_tx2.send(("split", total_split_time)).unwrap();
    });
    
    // 发送路径
    for path in path_vec {
        start_tx.send(path.to_string()).unwrap();
    }
    drop(start_tx);
    // 消费drop_rx
    for c in drop_rx {
        drop(c);
    }

    
    t1.join().unwrap();
    t2.join().unwrap();
    
    drop(time_tx);
    // 接收并打印计时结果
    for (phase, duration) in time_rx.iter() {
        println!("{} phase took: {:?}", phase, duration);
    }
}